package bbchess.util;

import bbchess.units.ChessBoard;
import bbchess.units.ChessPiece;
import bbchess.units.ChessSquare;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import javax.swing.JComponent;
import javax.swing.SwingUtilities;

/**
 * The glass pane over the main program window. Most of it's methods are for
 * animation.
 * @author Tyler Eastman
 */
public class ChessGlassPane extends JComponent {

    private boolean dragging;
    private boolean screenDisabled;

    private ChessPiece piece;
    private Point mouseLoc;
    private ChessBoard board;
    private int squareSize;
    private Thread dragThread;
    private DummyMouseListener dummyMouseListener;

    public ChessGlassPane() {
        // Disable the screen
        dummyMouseListener = new DummyMouseListener();
        screenDisabled = true;
        addMouseListener(dummyMouseListener);
        addMouseMotionListener(dummyMouseListener);

        dragging = false;
        mouseLoc = new Point();
    }

    public void setBoard(ChessBoard board) {
        this.board = board;
    }

    /**
     * Disables the screen to input and fades the screen black.
     * @param choice
     */
    public void setScreenDisabled(boolean choice) {
        screenDisabled = choice;
        repaint();

        // If the screen is disabled
        if (screenDisabled) {
            int i = board.gui.menuBar.getMenuCount();

            for (int x = 0; x < i; x++) {
                board.gui.menuBar.getMenu(x).setEnabled(false);
            }
        }
        // Else, re-enable mouse input
        else {
            int i = board.gui.menuBar.getMenuCount();

            for (int x = 0; x < i; x++) {
                board.gui.menuBar.getMenu(x).setEnabled(true);
            }
        }
    }

    public boolean isScreenDisabled() {
        return screenDisabled;
    }

    @Override
    public boolean contains(int x, int y) {
        return false;
    }

    /**
     * Called whenever a piece is dragged.
     * @param piece
     */
    public void startDragging(ChessPiece piece) {
        this.piece = piece;
        piece.setVisible(false);
        setVisible(true);
        squareSize = board.getSquareSize();
        dragging = true;
        dragThread = new Thread(new DragThread());
        dragThread.start();
    }

    /**
     * Called when a piece stops dragging.
     */
    public void stopDragging() {
        if (piece != null) {
            piece.setVisible(true);
            dragging = false;
            setVisible(false);
        }
    }

    /**
     * Starts moving piece to square from mousePosition. Currently not in use,
     * but with some modification will call MoveToSquare class to animate a the
     * movement of a piece to a square.
     * @param piece
     * @param square
     * @param mousePosition
     */
    public void moveToSquare(ChessPiece piece, ChessSquare square) {
        //new Thread(new MoveToSquare(piece, square)).start();
    }

    /**
     * Currently not in use, but with some work will animate the movement of
     * piece to square.
     */
    private class MoveToSquare implements Runnable {

        double startX;
        double startY;
        double endX;
        double endY;
        double movement;
        double offsetX;
        double offsetY;
        int iteration;
        int pieceX;
        int pieceY;
        int squareSize;
        ChessPiece piece;
        ChessSquare square;
        Point squareLoc;

        MoveToSquare(ChessPiece piece, ChessSquare square) {

            mouseLoc.setLocation(MouseInfo.getPointerInfo().getLocation().x,
                    MouseInfo.getPointerInfo().getLocation().y);

            squareLoc = new Point(square.getLocationOnScreen());

            SwingUtilities.convertPointFromScreen(mouseLoc, getParent());
            SwingUtilities.convertPointFromScreen(squareLoc, getParent());

            System.out.println("Mouse Location = " + mouseLoc);
            System.out.println("Square Location = " + squareLoc);

            piece.setMoving(true);
            startX = mouseLoc.x-(square.getWidth()/2);
            startY = mouseLoc.y-(square.getHeight()/2);
            endX = (double) squareLoc.x;
            endY = (double) squareLoc.y;
            iteration = 1;
            movement = .08;
            this.piece = piece;
            this.square = square;
            squareSize = square.getWidth();
        }

        public void run() {
            while (!isClose()) {

                pieceX = (int) (startX + (endX - startX) * (movement * iteration));
                pieceY = (int) (startY + (endX - startY) * (movement * iteration));

                getGraphics().drawImage(piece.getSprite(), (int) pieceX - (squareSize / 2),
                        (int) pieceY - (squareSize / 2), squareSize, squareSize, null);

                iteration++;

                try {
                    Thread.sleep(16);
                } catch (Exception ex) {
                }
            }
            piece.setMoving(false);
        }

        private boolean isClose() {
            int bounds = 20;

            if ((startX > endX) && (startY > endY)) {
                if ((piece.getX() >= endX + bounds) || (piece.getY() >= endY + bounds))
                    return false;
            }

            else if ((startX < endX) && (startY < endY)) {
                if ((piece.getX() <= endX - bounds) || (piece.getY() <= endY - bounds))
                    return false;
            }

            else if ((startX > endX) && (startY < endY)) {
                if ((piece.getX() >= endX + bounds) || (piece.getY() <= endY - bounds))
                    return false;
            }

            else if ((startX < endX) && (startY > endY)) {
                if ((piece.getX() <= endX - bounds) || (piece.getY() >= endY + bounds))
                    return false;
            }

            return true;
        }
    }

    @Override
    public void paint(Graphics g) {
        paintComponent(g);
    }

    @Override
    public void update(Graphics g) {
        paint(g);
    }
    
    @Override
    protected void paintComponent(Graphics g) {

        if (dragging) {

            mouseLoc.setLocation(MouseInfo.getPointerInfo().getLocation().x,
                    MouseInfo.getPointerInfo().getLocation().y);

            SwingUtilities.convertPointFromScreen(mouseLoc, this);

            g.drawImage(piece.getSprite(), (int) mouseLoc.x - (squareSize / 2),
                    (int) mouseLoc.y - (squareSize / 2), squareSize, squareSize, this);
        }

        // If the screen is disabled, paint it black yo! and disable input.
        if (screenDisabled) {
            g.setColor(new Color(0, 0, 0, 150));
            g.fillRect(0, board.gui.menuBar.getHeight(), getWidth(), getHeight());
        }
    }

    /**
     * Called whenever a piece is being dragged by the mouse, this repaints
     * the piece at the mouses location.
     */
    public class DragThread implements Runnable {

        public void run() {
            while (dragging) {

                repaint((int) mouseLoc.x - (squareSize / 2)*3,
                    (int) mouseLoc.y - (squareSize / 2)*3, squareSize*3, squareSize*3);

                try {
                    Thread.sleep(20);
                } catch (Exception ex) { }
            }
        }
    }

    /**
     * A dummy mouse listener to block mouse clicks when screen is disabled
     */
    private class DummyMouseListener implements MouseListener, MouseMotionListener {

        public void mouseClicked(MouseEvent me) {
            // Dont do a thing
        }

        public void mousePressed(MouseEvent me) {
            // Dont do a thing
        }

        public void mouseReleased(MouseEvent me) {
            // Dont do a thing
        }

        public void mouseEntered(MouseEvent me) {
            // Dont do a thing
        }

        public void mouseExited(MouseEvent me) {
            // Dont do a thing
        }

        public void mouseDragged(MouseEvent me) {
            // Dont do a thing
        }

        public void mouseMoved(MouseEvent me) {
            // Dont do a thing
        }

    }
}
